﻿//------------------------------------------------------------------------------
//	文件名称：WlniaoCMS\CMS.Model\News\NewsClass.cs
//	运 行 库：2.0.50727.1882
//	代码功能：栏目分类Model类
//	最后修改：2011年12月7日 23:35:52
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.ORM;
using System.IO;
using System.Web;
using System.Web.SessionState;
using System.Web.Configuration;
using System.Configuration;
using System.Configuration.Provider;
using System.Collections.Specialized;
using System.Data;
using System.Diagnostics;
namespace System
{
    public sealed class XCoreSessionStateStore : SessionStateStoreProviderBase
    {
        private SessionStateSection pConfig = null;
        private string exceptionMessage = "XCore状态存储服务出现异常.";
        private static string pApplicationName = "XCoreSession" + System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath.Replace("/", "").Replace("'", "");
        
        //
        // The ApplicationName property is used to differentiate sessions
        // in the data source by application.
        //

        public string ApplicationName
        {
            get { return pApplicationName; }
        }


        public override void Initialize(string name, NameValueCollection config)
        {
            //
            // Initialize values from web.config.
            //

            if (config == null)
                throw new ArgumentNullException("config");

            if (name == null || name.Length == 0)
            {
                name = "XCoreSessionStateStore";
            }

            if (String.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "XCore Session State Store provider");
            }

            // Initialize the abstract base class.
            base.Initialize(name, config);


            //
            // Get <sessionState> configuration element.
            //

            System.Configuration.Configuration cfg = WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
            pConfig = (SessionStateSection)cfg.GetSection("system.web/sessionState");

        }


        //
        // SessionStateStoreProviderBase members
        //

        public override void Dispose()
        {
        }


        //
        // SessionStateProviderBase.SetItemExpireCallback
        //

        public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)
        {
            return false;
        }


        //
        // SessionStateProviderBase.SetAndReleaseItemExclusive
        //

        public override void SetAndReleaseItemExclusive(HttpContext context,
          string id,
          SessionStateStoreData item,
          object lockId,
          bool newItem)
        {
            // Serialize the SessionStateItemCollection as a string.
            string sessItems = Serialize((SessionStateItemCollection)item.Items);
            if (newItem)
            {
                SessionsData.deleteBatch(string.Format("SessionId='{0}' and ApplicationName='{1}' and ExpiresTicks <{2}", id, ApplicationName, DateTime.Now.Ticks));

                SessionsData session = new SessionsData();
                session.SessionId = id;
                session.ApplicationName = ApplicationName;
                session.Created = DateTime.Now;
                try
                {
                    session.Expires = DateTime.Now.AddMinutes(pConfig.Timeout.Minutes);
                    session.Timeout = pConfig.Timeout.Minutes;
                }
                catch
                {
                    session.Expires = DateTime.Now.AddMinutes(120);
                    session.Timeout = 120;
                }
                session.ExpiresTicks = session.Expires.Ticks;
                session.LockDate = DateTime.Now;
                session.LockId = 0;
                session.Locked = false;
                session.SessionItems = sessItems;
                session.Flags = 0;
                session.insert();
            }
            else
            {
                try
                {
                    SessionsData session = SessionsData.find(string.Format("SessionId='{0}' and ApplicationName='{1}' and LockId={2} ", id, ApplicationName, lockId)).first();

                    session.Expires = DateTime.Now.AddMinutes(pConfig.Timeout.Minutes);
                    session.ExpiresTicks = session.Expires.Ticks;
                    session.LockDate = DateTime.Now;
                    session.Timeout = pConfig.Timeout.Minutes;
                    session.Locked = false;
                    session.SessionItems = sessItems;
                    session.Flags = 0;
                    session.update();
                }
                catch(Exception e)
                {
                    WriteToEventLog(e, "SetAndReleaseItemExclusive");
                }
            }
        }


        //
        // SessionStateProviderBase.GetItem
        //

        public override SessionStateStoreData GetItem(HttpContext context,
          string id,
          out bool locked,
          out TimeSpan lockAge,
          out object lockId,
          out SessionStateActions actionFlags)
        {
            return GetSessionStoreItem(false, context, id, out locked,
              out lockAge, out lockId, out actionFlags);
        }


        //
        // SessionStateProviderBase.GetItemExclusive
        //

        public override SessionStateStoreData GetItemExclusive(HttpContext context,
          string id,
          out bool locked,
          out TimeSpan lockAge,
          out object lockId,
          out SessionStateActions actionFlags)
        {
            return GetSessionStoreItem(true, context, id, out locked,
              out lockAge, out lockId, out actionFlags);
        }


        //
        // GetSessionStoreItem is called by both the GetItem and 
        // GetItemExclusive methods. GetSessionStoreItem retrieves the 
        // session data from the data source. If the lockRecord parameter
        // is true (in the case of GetItemExclusive), then GetSessionStoreItem
        // locks the record and sets a new LockId and LockDate.
        //

        private SessionStateStoreData GetSessionStoreItem(bool lockRecord,
          HttpContext context,
          string id,
          out bool locked,
          out TimeSpan lockAge,
          out object lockId,
          out SessionStateActions actionFlags)
        {
            // Initial values for return value and out parameters.
            SessionStateStoreData item = null;
            lockAge = TimeSpan.Zero;
            lockId = null;
            locked = false;
            actionFlags = 0;

            // DateTime to check if current session item is expired.
            DateTime expires;
            // String to hold serialized SessionStateItemCollection.
            string serializedItems = "";
            // True if a record is found in the database.
            bool foundRecord = false;
            // True if the returned session item is expired and needs to be deleted.
            bool deleteData = false;
            // Timeout value from the data store.
            int timeout = 0;

            try
            {

                // lockRecord is true when called from GetItemExclusive and
                // false when called from GetItem.
                // Obtain a lock if possible. Ignore the record if it is expired.
                SessionsData session = null;
                if (lockRecord)
                {
                    try
                    {
                        session = SessionsData.find(string.Format("SessionId='{0}' and ApplicationName='{1}' and Locked=0 and ExpiresTicks>{2} ", id, ApplicationName, DateTime.Now.Ticks.ToString())).first();
                        session = db.nocache.findById<SessionsData>(session.Id);
                        if (session != null)
                        {
                            try
                            {
                                session.Expires = DateTime.Now.AddMinutes(pConfig.Timeout.Minutes);
                                session.Timeout = pConfig.Timeout.Minutes;
                            }
                            catch
                            {
                                session.Expires = DateTime.Now.AddMinutes(120);
                                session.Timeout = 120;
                            }
                            session.ExpiresTicks = session.Expires.Ticks;
                            session.LockDate = DateTime.Now;
                            session.Locked = false;
                            session.update();
                            locked = false;
                        }
                    }
                    catch (Exception e)
                    {
                        WriteToEventLog(e, "GetSessionStoreItem");
                    }
                }
                try
                {
                    if (session == null)
                    {
                        session = SessionsData.find(string.Format("SessionId='{0}' and ApplicationName='{1}' and LockId={2} ", id, ApplicationName, lockId)).first();
                    }
                    if (session != null)
                    {
                        if (session.Expires < DateTime.Now)
                        {
                            // The record was expired. Mark it as not locked.
                            locked = false;
                            // The session was expired. Mark the data for deletion.
                            deleteData = true;
                        }
                        else
                            foundRecord = true;

                        serializedItems = session.SessionItems;
                        lockId = session.LockId;
                        lockAge = DateTime.Now.Subtract(session.LockDate);
                        actionFlags = (SessionStateActions)session.Flags;
                        timeout = session.Timeout;
                    }
                }
                catch { }


                // If the returned session item is expired, 
                // delete the record from the data source.
                if (deleteData)
                {
                    SessionsData.deleteBatch(string.Format("SessionId='{0}' and ApplicationName='{1}' ", id, ApplicationName, DateTime.Now.Ticks));
                }

                // The record was not found. Ensure that locked is false.
                if (!foundRecord)
                    locked = false;

                // If the record was found and you obtained a lock, then set 
                // the lockId, clear the actionFlags,
                // and create the SessionStateStoreItem to return.
                if (foundRecord && !locked)
                {
                    lockId = (int)lockId + 1;

                    SessionsData.updateBatch(string.Format("LockId = {0}, Flags = 0 ", lockId), string.Format("SessionId='{0}' and ApplicationName='{1}' ", id, ApplicationName, DateTime.Now.Ticks));

                    // If the actionFlags parameter is not InitializeItem, 
                    // deserialize the stored SessionStateItemCollection.
                    if (actionFlags == SessionStateActions.InitializeItem)
                        item = CreateNewStoreData(context, pConfig.Timeout.Minutes);
                    else
                        item = Deserialize(context, serializedItems, timeout);
                }
            }
            catch (Exception e)
            {
                WriteToEventLog(e, "GetSessionStoreItem");
            }
            return item;
        }

        public static void SetSessionValue(string itemKey, object itemValue, HttpContext ctx = null)
        {
            if (ctx == null)
            {
                ctx = HttpContext.Current;
            }
            if (ctx.Session == null)
            {
                string sessionid = ctx.Request.Params.Get("ASP.NET_SessionId");
                SessionsData session = SessionsData.find(string.Format("SessionId='{0}' and ApplicationName='{1}'", sessionid, pApplicationName)).first();
                SessionStateItemCollection sessionItems = new SessionStateItemCollection();
                if (session == null)
                {
                    session = new SessionsData();
                    session.SessionId = sessionid;
                    session.ApplicationName = pApplicationName;
                    session.Created = DateTime.Now;

                    sessionItems[itemKey] = itemValue;
                }
                else
                {
                    MemoryStream ms = new MemoryStream(Convert.FromBase64String(session.SessionItems));
                    if (ms.Length > 0)
                    {
                        BinaryReader reader = new BinaryReader(ms);
                        sessionItems = SessionStateItemCollection.Deserialize(reader);
                    }
                    sessionItems[itemKey] = itemValue;
                }
                MemoryStream msw = new MemoryStream();
                BinaryWriter writer = new BinaryWriter(msw);
                sessionItems.Serialize(writer);
                writer.Close();
                session.SessionItems = Convert.ToBase64String(msw.ToArray());

                session.Expires = DateTime.Now.AddMinutes(120);
                session.ExpiresTicks = session.Expires.Ticks;
                session.LockDate = DateTime.Now;
                session.Timeout = 120;
                session.Locked = false;
                session.Flags = 0;
                session.save();
            }
            else
            {
                ctx.Session[itemKey]=itemValue;
            }
        }
        public static SessionStateStoreData GetSessionById(HttpContext ctx,string sessionid)
        {
            try
            {
                SessionsData session = SessionsData.find(string.Format("SessionId='{0}' and ApplicationName='{1}' ", sessionid, pApplicationName)).first();
                
                MemoryStream ms =
                  new MemoryStream(Convert.FromBase64String(session.SessionItems));

                SessionStateItemCollection sessionItems =
                  new SessionStateItemCollection();

                if (ms.Length > 0)
                {
                    BinaryReader reader = new BinaryReader(ms);
                    sessionItems = SessionStateItemCollection.Deserialize(reader);
                }

                return new SessionStateStoreData(sessionItems,
                  SessionStateUtility.GetSessionStaticObjects(ctx),
                  session.Timeout);
            }
            catch (Exception e)
            {
            }
            return null;
        }
        public static Object GetSessionValue(string itemKey, HttpContext ctx = null)
        {
            if (ctx == null)
            {
                ctx = HttpContext.Current;
            }
            if (ctx.Session == null)
            {
                return GetSessionById(ctx, ctx.Request.Params.Get("ASP.NET_SessionId")).Items[itemKey];
            }
            else
            {
                return ctx.Session[itemKey];
            }
        }
        public static String GetSessionValueStr(string itemKey, HttpContext ctx = null)
        {
            if (ctx == null)
            {
                ctx = HttpContext.Current;
            }
            try
            {
                if (ctx.Session == null)
                {
                    return GetSessionById(ctx, ctx.Request.Params.Get("ASP.NET_SessionId")).Items[itemKey].ToString();
                }
                else
                {
                    return ctx.Session[itemKey].ToString();
                }
            }
            catch
            {
                return "";
            }
        }

        //
        // Serialize is called by the SetAndReleaseItemExclusive method to 
        // convert the SessionStateItemCollection into a Base64 string to    
        // be stored in an Access Memo field.
        //

        private string Serialize(SessionStateItemCollection items)
        {
            MemoryStream ms = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(ms);

            if (items != null)
                items.Serialize(writer);

            writer.Close();

            return Convert.ToBase64String(ms.ToArray());
        }

        //
        // DeSerialize is called by the GetSessionStoreItem method to 
        // convert the Base64 string stored in the Access Memo field to a 
        // SessionStateItemCollection.
        //

        private SessionStateStoreData Deserialize(HttpContext context,
          string serializedItems, int timeout)
        {
            MemoryStream ms =
              new MemoryStream(Convert.FromBase64String(serializedItems));

            SessionStateItemCollection sessionItems =
              new SessionStateItemCollection();

            if (ms.Length > 0)
            {
                BinaryReader reader = new BinaryReader(ms);
                sessionItems = SessionStateItemCollection.Deserialize(reader);
            }

            return new SessionStateStoreData(sessionItems,
              SessionStateUtility.GetSessionStaticObjects(context),
              timeout);
        }

        //
        // SessionStateProviderBase.ReleaseItemExclusive
        //

        public override void ReleaseItemExclusive(HttpContext context,
          string id,
          object lockId)
        {
            try
            {
                SessionsData.updateBatch(string.Format("LockId=0, Expires='{1}' ", DateTime.Now.AddMinutes(pConfig.Timeout.Minutes).ToString("yyyy-MM-dd HH:mm:ss"), lockId), string.Format("SessionId='{0}' and ApplicationName='{1}' and LockId={2}", id, ApplicationName, lockId));
            }
            catch (Exception e)
            {
                WriteToEventLog(e, "ReleaseItemExclusive");
            }
        }


        //
        // SessionStateProviderBase.RemoveItem
        //

        public override void RemoveItem(HttpContext context,
          string id,
          object lockId,
          SessionStateStoreData item)
        {
            try
            {
                SessionsData.deleteBatch(string.Format("SessionId='{0}' and ApplicationName='{1}' and LockId={2} ", id, ApplicationName, lockId));
            }
            catch (Exception e)
            {
                WriteToEventLog(e, "RemoveItem");
                throw new ProviderException(exceptionMessage);
            }
        }



        //
        // SessionStateProviderBase.CreateUninitializedItem
        //

        public override void CreateUninitializedItem(HttpContext context,
          string id,
          int timeout)
        {
            try
            {
                SessionsData session = new SessionsData();
                session.SessionId = id;
                session.ApplicationName = ApplicationName;
                session.Created = DateTime.Now;
                session.Expires = DateTime.Now.AddMinutes(timeout);
                session.ExpiresTicks = session.Expires.Ticks;
                session.LockDate = DateTime.Now;
                session.LockId = 0;
                session.Timeout = timeout;
                session.Locked = false;
                session.SessionItems = "";
                session.Flags = 0;
                session.insert();
            }
            catch (Exception e)
            {
                WriteToEventLog(e, "CreateUninitializedItem");
            }
        }


        //
        // SessionStateProviderBase.CreateNewStoreData
        //

        public override SessionStateStoreData CreateNewStoreData(
          HttpContext context,
          int timeout)
        {
            return new SessionStateStoreData(new SessionStateItemCollection(),
              SessionStateUtility.GetSessionStaticObjects(context),
              timeout);
        }



        //
        // SessionStateProviderBase.ResetItemTimeout
        //

        public override void ResetItemTimeout(HttpContext context,
                                              string id)
        {
            try
            {
                SessionsData session = SessionsData.find(string.Format("SessionId='{0}' and ApplicationName='{1}' ", id, ApplicationName)).first();
                session.Expires = DateTime.Now.AddMinutes(pConfig.Timeout.Minutes);
                session.ExpiresTicks = session.Expires.Ticks;
                session.update();
            }
            catch (Exception e)
            {
                WriteToEventLog(e, "ResetItemTimeout");
            }
        }


        //
        // SessionStateProviderBase.InitializeRequest
        //

        public override void InitializeRequest(HttpContext context)
        {
        }


        //
        // SessionStateProviderBase.EndRequest
        //

        public override void EndRequest(HttpContext context)
        {
            try
            {
                SessionsData.deleteBatch(string.Format("ExpiresTicks<{0} ", DateTime.Now.Ticks));
            }
            catch (Exception e)
            {
                WriteToEventLog(e, "EndRequest");
                throw new ProviderException(exceptionMessage);
            }
        }


        //
        // WriteToEventLog
        // This is a helper function that writes exception detail to the 
        // event log. Exceptions are written to the event log as a security
        // measure to ensure private database details are not returned to 
        // browser. If a method does not return a status or Boolean
        // indicating the action succeeded or failed, the caller also 
        // throws a generic exception.
        //

        private void WriteToEventLog(Exception e, string action)
        {
            ILog log = LogManager.GetLogger();
            //log.Source = eventSource;
            //log.Log = eventLog;

            string message =
              "An exception occurred communicating with the data source.\n\n";
            message += "Action: " + action + "\n\n";
            message += "Exception: " + e.ToString();

            log.Error(message);
        }
    }
}